package licode.unisop.auth.application.uniclient;

import cn.hutool.core.util.StrUtil;
import licode.unisop.client.api.auth.SopResourceQuery;
import licode.unisop.client.api.auth.SopUserAuthQuery;
import licode.unisop.client.info.SopTokenInfo;
import licode.unisop.client.vo.*;
import licode.unisop.provider.api.SiOauthProvider;
import licode.unisop.provider.info.TokenIdInfo;
import licode.unisop.provider.info.UserIdInfo;
import licode.unisop.provider.vo.SiProps;
import licode.unisop.provider.vo.SiUser;
import licode.unisop.realm.client.api.SiUserQueryService;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * 实现用户资源获取
 *
 * @author licode
 */
@Primary
@Service
public class SopUserAuthQueryImpl implements SopUserAuthQuery {
    @Resource
    private SiOauthProvider siOauthProvider;

    @Resource
    private SopResourceQuery sopResourceQuery;

    @Resource
    private SiUserQueryService siUserQueryService;

    @Override
    public SopAuthBrief getAuthBrief(SopTokenInfo tokenInfo) {
        SopCredential credential = getCredential(tokenInfo.getToken());
        if (null != credential) {
            return credential.getBrief();
        }
        return null;
    }

    @Override
    public SopAuthUser getAuthUserInfo(SopTokenInfo tokenInfo) {
        SopAuthUser authUser = null;
        SopUserBrief sopUserBrief = null;
        SopCredential credential = getCredential(tokenInfo.getToken());

        if (null != credential) {
            authUser = new SopAuthUser();
            SiUser siUser = siUserQueryService.lookupUserById(UserIdInfo.builder()
                    .realmId(credential.getBrief().getRealmId())
                    .userId(credential.getBrief().getUserId())
                    .build());
            SiProps props = siUser.getProps() == null ? SiProps.EMPTY : siUser.getProps();
            sopUserBrief = SopUserBrief.builder()
                    .userId(siUser.getId())
                    .name(siUser.getName())
                    .nickName(props.getString("nickName", ""))
                    .avatar(props.getString("avatar", ""))
                    .signature(props.getString("signature", ""))
                    .mobile(props.getString("mobile", ""))
                    .gender(props.getString("gender", ""))
                    .build();
            props.removeProp("nickName");
            props.removeProp("avatar");
            props.removeProp("gender");
            props.removeProp("signature");
            props.removeProp("mobile");
            if (SiProps.EMPTY != siUser.getProps()) {
                sopUserBrief.setProps(siUser.getProps().toMap());
            }

            authUser.setUser(sopUserBrief);
            authUser.setCred(credential);
        }

        return authUser;
    }

    @Override
    public SopUserBrief getUserInfo(SopTokenInfo tokenInfo) {
        SopAuthUser authUser = getAuthUserInfo(tokenInfo);
        if (null != authUser) {
            return authUser.getUser();
        } else {
            return null;
        }
    }

    @Override
    public SopCredential getCredential(SopTokenInfo tokenInfo) {
        return getCredential(tokenInfo.getToken());
    }

    @Override
    public boolean tokenValid(SopTokenInfo tokenInfo) {
        if (StrUtil.isBlank(tokenInfo.getToken())) {
            return false;
        }
        return siOauthProvider.isLogin(TokenIdInfo
                .builder()
                .token(tokenInfo.getToken())
                .build());
    }

    public Map<String, Object> getUserAssets(SopTokenInfo tokenInfo) {
        Map<String, Object> result = new HashMap<>();
        SopUserAssets userAsset = sopResourceQuery.getUserAssets(tokenInfo);

        if (null == userAsset) {
            return new HashMap<>();
        }

        result.put("menus", userAsset.getMenus());

        if (null != userAsset.getRoleCodes()) {
            Map<String, String> roleCodes = userAsset.getRoleCodes();
            result.put("roleCodes", new ArrayList<>(roleCodes.keySet()));
        }

        if (null != userAsset.getPermitCodes()) {
            Map<String, String> permitCodes = userAsset.getPermitCodes();
            result.put("permitCodes", new ArrayList<>(permitCodes.keySet()));
        }

        return result;
    }

    private SopCredential getCredential(String accessToken) {
        Map<String, Object> oidcToken;
        oidcToken = siOauthProvider.getCredential(TokenIdInfo
                .builder()
                .token(accessToken)
                .build());
        if (null != oidcToken) {
            return fromOidcToken(oidcToken);
        } else {
            return null;
        }
    }

    private SopCredential fromOidcToken(Map<String, Object> oidcToken) {
        SiProps props = SiProps.build(oidcToken);
        return SopCredential.builder()
                .brief(SopAuthBrief.builder()
                        .userId(props.getString("userId", ""))
                        .tenantId(props.getString("tenantId", ""))
                        .clientId(props.getString("clientId", ""))
                        .platformId(props.getString("platformId", ""))
                        .realmId(props.getString("realmId", ""))
                        .account(props.getString("account", ""))
                        .authType(props.getString("authType", ""))
                        .roleCodes(props.getString("roleCodes", ""))
                        .roleNames(props.getString("roleNames", ""))
                        .terminalId(props.getString("terminalId", ""))
                        .userType(props.getString("userType", ""))
                        .build())
                .accessToken(props.getString("accessToken", ""))
                .accessExpired(props.getLong("accessExpired", 300L))
                .refreshToken(props.getString("refreshToken", ""))
                .refreshExpired(props.getLong("refreshExpired", 300L))
                .build();
    }
}
